#include "vbb_RTC.h"
#include "vbb_Utils.h"
#include <time.h>

unsigned int _rtc_time_offset;

unsigned int vbb_RTC_GetSec(void)
{
    unsigned short tmp = RTC->CNTL;
    return (((unsigned int)RTC->CNTH << 16 ) | tmp);
}

unsigned int vbb_RTC_GetCurrSec(void)
{
    return vbb_RTC_GetSec() + _rtc_time_offset;
}

void vbb_RTC_Init(VBB_RTC * Rtc)
{
    if (vbb_BACKUP_Get(SAVE_RTC) == 0xAAAA)
    {
        _rtc_time_offset = 0;
        _rtc_time_offset |= (((vbb_BACKUP_Get(SAVE_RTC_TIMEOFFSET) & 0xFFFF) << 16) & 0xFFFF0000);
        _rtc_time_offset |= (vbb_BACKUP_Get(SAVE_RTC_TIMEOFFSET + 1) & 0xFFFF);
    }
    else
    {            
        //vbb_BACKUP_Clear();
        
        RCC->APB1ENR |= RCC_APB1ENR_PWREN; // Enable Power for Interface of Clock
        RCC->APB1ENR |= RCC_APB1ENR_BKPEN; // Backup Interface of Clock
        
        PWR->CR |= PWR_CR_DBP; // Enable Access to RTC registers
        
        RCC->BDCR |= RCC_BDCR_LSEON;
        while ((RCC->BDCR & RCC_BDCR_LSERDY) == 0);
        RCC->BDCR |= (RCC_BDCR_RTCEN | RCC_BDCR_RTCSEL_0);
        
        RTC->CRL &= ~RTC_CRL_RSF;
        while ((RTC->CRL & RTC_CRL_RSF) == 0);
        
        while ((RTC->CRL & RTC_CRL_RTOFF) == 0);
        
        RTC->CRH |= RTC_CRH_SECIE;
        RTC->CRH &= ~RTC_CRH_ALRIE;
        RTC->CRH &= ~RTC_CRH_OWIE;
        
        while ((RTC->CRL & RTC_CRL_RTOFF) == 0);
        
        RTC->CRL |= RTC_CRL_CNF;
        RTC->PRLH = (32767 & 0x000F0000) >> 16;
        RTC->PRLL = (32767 & 0x0000FFFF);
        RTC->CRL &= ~RTC_CRL_CNF;
        
        while ((RTC->CRL & RTC_CRL_RTOFF) == 0);        
        
        vbb_OUTPUT_Print("INFO: Enable RTC and clear system backup.\r\n");        
        vbb_BACKUP_Set(SAVE_RTC, 0xAAAA);        
        vbb_DelayMillis(1000);
        
        //vbb_Reset();
    }
}

void vbb_RTC_Set(unsigned int NewTime)
{
    if (NewTime > 0)
    {
        _rtc_time_offset = NewTime - vbb_RTC_GetSec();
        
        vbb_BACKUP_Set(SAVE_RTC_TIMEOFFSET, ((_rtc_time_offset >> 16) & 0xFFFF));
        vbb_BACKUP_Set(SAVE_RTC_TIMEOFFSET + 1, (_rtc_time_offset & 0xFFFF));
    }
}

time_t rtc_time;
struct tm * local_time;

void vbb_RTC_Update(VBB_RTC * Rtc)
{   
    rtc_time = vbb_RTC_GetCurrSec();
    local_time = localtime(&rtc_time);
    Rtc->hour = local_time->tm_hour;
    Rtc->minute = local_time->tm_min;
    Rtc->second = local_time->tm_sec;
    Rtc->day = local_time->tm_mday;
    Rtc->month = local_time->tm_mon + 1;
    Rtc->year = local_time->tm_year + 1900;
}

void vbb_RTC_Convert(unsigned int Time, int * HourMinSec, int * DayMonthYear)
{
    rtc_time = Time;
    local_time = localtime(&rtc_time);
    HourMinSec[0] = local_time->tm_hour;
    HourMinSec[1] = local_time->tm_min;
    HourMinSec[2] = local_time->tm_sec;
    DayMonthYear[0] = local_time->tm_mday;
    DayMonthYear[1] = local_time->tm_mon + 1;
    DayMonthYear[2] = local_time->tm_year + 1900;
}

void vbb_RTC_Save(VBB_RTC * Rtc, unsigned int CurrentSec)
{    
    while ((RTC->CRL & RTC_CRL_RTOFF) == 0);
    RTC->CRL |= RTC_CRL_CNF;
    RTC->CNTH = CurrentSec >> 16;
    RTC->CNTL = CurrentSec;
    RTC->CRL &= ~RTC_CRL_CNF;
    while ((RTC->CRL & RTC_CRL_RTOFF) == 0);
}
